#include "GRectangleAligned.h"							
#include "GCircle.h"

#include <math.h>

namespace GMath
{
	const GRectangleAligned	GRectangleAligned::UnitRectangle = GRectangleAligned(GVector2(-0.5f, -0.5f),
																				GVector2( 0.5f,  0.5f));

	GRectangleAligned::GRectangleAligned()
	{
		Create(GVector2::Zero, 0.0f, 0.0f);
	}

	GRectangleAligned::GRectangleAligned(const GVector2& TheMin, const GVector2& TheMax)
	{
		Create(TheMin, TheMax);
	}

	GRectangleAligned::GRectangleAligned(const GVector2& Center, float Width, float Height)
	{
		Create(Center, Width, Height);
	}

	void GRectangleAligned::Create(const GVector2& TheMin, const GVector2& TheMax)
	{
		Min = TheMin;
		Max = TheMax;
	}
	
	void GRectangleAligned::Create(const GVector2& Center, float Width, float Height)
	{
		Min = Center - GVector2(Width , Height) / 2.0f;
		Max = Center + GVector2(Width , Height) / 2.0f;
	}
	
	GVector2 GRectangleAligned::GetDimension() const
	{
		return Max - Min;
	}
	
	const GVector2& GRectangleAligned::GetCenter() const
	{
		return (Min + Max) / 2.0f;
	}

	const GVector2& GRectangleAligned::GetUp() const
	{
		return GVector2::UnitY;
	}

	const GVector2& GRectangleAligned::GetRight() const
	{
		return GVector2::UnitX;
	}

	float GRectangleAligned::Area() const
	{
		GVector2 Dimension = GetDimension();
		return Dimension.x * Dimension.y;
	}

	float GRectangleAligned::Circumference() const
	{
		GVector2 Dimension = GetDimension();
		return (Dimension.x + Dimension.y) * 2.0f;
	}

	void GRectangleAligned::GetCorners(OUTPUT GVector2 Arr[G_RC_COUNT]) const
	{
		Arr[G_RC_BOTTOM_LEFT]	= GVector2(Min.x, Min.y);
		Arr[G_RC_BOTTOM_RIGHT]	= GVector2(Max.x, Min.y);
		Arr[G_RC_TOP_LEFT]		= GVector2(Min.x, Max.y);
		Arr[G_RC_TOP_RIGHT]		= GVector2(Max.x, Max.y);
	}

	#define		G_BOX_X_AXIS		(GUInt32)0x01
	#define		G_BOX_Y_AXIS		(GUInt32)0x02

	GVector2 GRectangleAligned::GetCorner(GRectangleCorner Corner) const
	{
		return GVector2((Corner & G_BOX_X_AXIS) ? Max.x : Min.x, 
						(Corner & G_BOX_Y_AXIS) ? Max.y : Min.y);
	}
	
	void GRectangleAligned::Combine(const GRectangleAligned& Rect)
	{
		GRectangleAligned Temp(*this);
		GRectangleAligned::Combine(*this, Temp, Rect);
	}

	void GRectangleAligned::Combine(OUTPUT GRectangleAligned& OutRect, const GRectangleAligned& Rect1, const GRectangleAligned& Rect2)
	{
		OutRect.Min.x = (Rect1.Min.x < Rect2.Min.x) ? Rect1.Min.x : Rect2.Min.x;
		OutRect.Max.x = (Rect1.Max.x > Rect2.Max.x) ? Rect1.Max.x : Rect2.Max.x;

		OutRect.Min.y = (Rect1.Min.y < Rect2.Min.y) ? Rect1.Min.y : Rect2.Min.y;
		OutRect.Max.y = (Rect1.Max.y > Rect2.Max.y) ? Rect1.Max.y : Rect2.Max.y;
	}

	void GRectangleAligned::Convert(OUTPUT GRectangleAligned& OutRect, const GRectangleOriented& Rect)
	{
		GVector2 Corners[G_RC_COUNT];
		Rect.GetCorners(Corners);
		
		// iterate all corners of rectangle and find min max for each axis.
		GVector2 Min = Corners[0]; 
		GVector2 Max = Corners[0];
		for (GSize I = 1; I < G_RC_COUNT; ++I)
		{
			if (Corners[I].x < Min.x)
			{
				Min.x = Corners[I].x;
			}
			else if (Corners[I].x > Max.x)
			{
				Max.x = Corners[I].x;
			}

			if (Corners[I].y < Min.y)
			{
				Min.y = Corners[I].y;
			}
			else if (Corners[I].y > Max.y)
			{
				Max.y = Corners[I].y;
			}
		}

		OutRect.Create(Min, Max);
	}
	
	void GRectangleAligned::Convert(OUTPUT GRectangleOriented& OutRect, const GRectangleAligned& Rect)
	{
		OutRect.Create(Rect.GetCenter(), Rect.GetDimension(), Rect.GetRight(), Rect.GetUp());
	}
	
	const GRectangleAligned& GRectangleAligned::operator = (const GRectangleAligned& Other)
	{
		Min = Other.Min;
		Max = Other.Max;

		return *this;
	}

}